package com.shrcl.engineerprocess.domain.impl;

import com.google.common.base.Objects;
import com.shrcl.engineerprocess.domain.ActorsDAO;
import com.shrcl.engineerprocess.domain.CreateProjectPlanTask;
import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerCostEstimation;
import com.shrcl.engineerprocess.domain.EngineerProcessSequenceService;
import com.shrcl.engineerprocess.domain.EngineerProject;
import com.shrcl.engineerprocess.domain.EngineerProjectJob;
import com.shrcl.engineerprocess.domain.EngineerProjectStatus;
import com.shrcl.engineerprocess.domain.impl.CreateProjectPlanTaskImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerCostEstimationImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerProjectJobImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerProjectProxy;
import com.shrct.businessprocess.organization.RCEmployee;
import com.shrct.businessprocess.project.RCProject;
import com.uniquesoft.uidl.validation.Validates;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.langlab.domain.task.TSKTask;
import edu.fudan.langlab.domain.task.TSKTaskDAO;
import edu.fudan.langlab.domain.task.TSKTaskOwner;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.utils.DateUtil;
import java.util.Collection;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERPROJECT_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineerproject")
public class EngineerProjectImpl extends BaseModelObject implements EngineerProject {
  public EngineerProjectImpl() {
    super();
  }
  
  private EngineerProjectStatus Status;
  
  public EngineerProjectStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    Status=EngineerProjectStatus.created;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _kickoff() {
    
    this.createProjectPlanTask();
    Status=EngineerProjectStatus.kicked;
  }
  
  public void kickoff() {
    if(Status==EngineerProjectStatus.created){
    	_kickoff();
    	getModelObjectLogService().createLog(this,"Status","kickoff");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectEventsManager.class).fireKickoff(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _finish() {
    
    Status=EngineerProjectStatus.finished;
  }
  
  public void finish() {
    if(Status==EngineerProjectStatus.kicked){
    	_finish();
    	getModelObjectLogService().createLog(this,"Status","finish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectEventsManager.class).fireFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private EngineerProjectJob _addProjectJob(final Procedure1<? super EngineerProjectJob> init) {
    EngineerProjectJob _createAndAddtoProjectJobs = this.createAndAddtoProjectJobs();
    final Procedure1<EngineerProjectJob> _function = new Procedure1<EngineerProjectJob>() {
        public void apply(final EngineerProjectJob it) {
          init.apply(it);
          BeanFactory _beanFactory = EngineerProjectImpl.this.getBeanFactory();
          EngineerProcessSequenceService _bean = _beanFactory.<EngineerProcessSequenceService>getBean(EngineerProcessSequenceService.class);
          String _nextEngineerProjectJobSequence = _bean.getNextEngineerProjectJobSequence();
          it.setSid(_nextEngineerProjectJobSequence);
        }
      };
    EngineerProjectJob _doubleArrow = ObjectExtensions.<EngineerProjectJob>operator_doubleArrow(_createAndAddtoProjectJobs, _function);
    return _doubleArrow;
  }
  
  public EngineerProjectJob addProjectJob(final Procedure1<? super EngineerProjectJob> init) {
    if(Status==EngineerProjectStatus.kicked){
    	EngineerProjectJob result = _addProjectJob(init);
    	getModelObjectLogService().createLog(this,"Status","addProjectJob");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectEventsManager.class).fireAddProjectJob(this,init);
    	return result;						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("Status.name()");
    }
  }
  
  private void _delProjectJob(final EngineerProjectJob engineerProjectJob) {
    
    this.removeFromProjectJobs(engineerProjectJob);
  }
  
  public void delProjectJob(final EngineerProjectJob engineerProjectJob) {
    if(Status==EngineerProjectStatus.kicked){
    	_delProjectJob(engineerProjectJob);
    	getModelObjectLogService().createLog(this,"Status","delProjectJob");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectEventsManager.class).fireDelProjectJob(this,engineerProjectJob);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerProjectStatus.created==Status;
  }
  
  public Boolean isKicked() {
    return com.shrcl.engineerprocess.domain.EngineerProjectStatus.kicked==Status;
  }
  
  public Boolean isFinished() {
    return com.shrcl.engineerprocess.domain.EngineerProjectStatus.finished==Status;
  }
  
  @JoinColumn(name = "tscCostEstimation_id")
  @ManyToOne(targetEntity = EngineerCostEstimationImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private EngineerCostEstimation tscCostEstimation;
  
  public EngineerCostEstimation getTscCostEstimation() {
    return this.tscCostEstimation;
  }
  
  public EngineerProject setTscCostEstimation(final EngineerCostEstimation tscCostEstimation) {
    this.tscCostEstimation = tscCostEstimation;
    return this;			
    
  }
  
  @JoinColumn(name = "projectManager_id")
  @ManyToOne(targetEntity = EngineerImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Engineer projectManager;
  
  public Engineer getProjectManager() {
    return this.projectManager;
  }
  
  public EngineerProject setProjectManager(final Engineer projectManager) {
    this.projectManager = projectManager;
    return this;			
    
  }
  
  @JoinColumn(name = "techLeader_id")
  @ManyToOne(targetEntity = EngineerImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Engineer techLeader;
  
  public Engineer getTechLeader() {
    return this.techLeader;
  }
  
  public EngineerProject setTechLeader(final Engineer techLeader) {
    this.techLeader = techLeader;
    return this;			
    
  }
  
  @ManyToMany(targetEntity = EngineerImpl.class)
  @JoinTable(name = "m2m_engineerproject_teammembers", joinColumns = @JoinColumn(name = "engineerproject_id") , inverseJoinColumns = @JoinColumn(name = "engineer_inv_id") )
  private Collection<Engineer> teamMembers = new java.util.ArrayList<com.shrcl.engineerprocess.domain.Engineer>();;
  
  public Collection<Engineer> getTeamMembers() {
    return this.teamMembers;
  }
  
  public EngineerProject setTeamMembers(final Iterable<Engineer> teamMembers) {
    removeAllTeamMembers();
    for(Engineer ca : teamMembers){
    	addtoTeamMembers(ca);
    }
    return this;		
    
  }
  
  public EngineerProject addtoTeamMembers(final Engineer engineer) {
    this.teamMembers.add(engineer);
    return this;
    
  }
  
  public EngineerProject removeAllTeamMembers() {
    this.teamMembers.clear();
    return this;	
    
  }
  
  public EngineerProject removeFromTeamMembers(final Engineer engineer) {
    this.teamMembers.remove(engineer);
    return this;
    
  }
  
  public RCProject getCBDProject() {
    RCProject _project = this.tscCostEstimation.getProject();
    return _project;
  }
  
  private void createProjectPlanTask() {
    BeanFactory _beanFactory = this.getBeanFactory();
    final TSKTaskDAO taskDAO = _beanFactory.<TSKTaskDAO>getBean(TSKTaskDAO.class);
    BeanFactory _beanFactory_1 = this.getBeanFactory();
    final ActorsDAO actorsDAO = _beanFactory_1.<ActorsDAO>getBean(ActorsDAO.class);
    RCEmployee _employee = this.projectManager==null?(RCEmployee)null:this.projectManager.getEmployee();
    final TSKTaskOwner tskOwner = actorsDAO.asTSKTaskOwner(_employee);
    boolean _notEquals = (!Objects.equal(tskOwner, null));
    Validates.Assert(_notEquals, "\u9879\u76EE\u7ECF\u7406\u4E0D\u80FD\u4E3A\u7A7A");
    final Procedure1<TSKTask> _function = new Procedure1<TSKTask>() {
        public void apply(final TSKTask it) {
          Date _now = DateUtil.now();
          it.setGenDate(_now);
          Date _now_1 = DateUtil.now();
          it.setStartTime(_now_1);
          it.start();
          it.startProcess();
        }
      };CreateProjectPlanTask createProjectPlanTask=CreateProjectPlanTaskImpl.create(getObjectFactory());
    final Procedure1<CreateProjectPlanTask> _function_1 = new Procedure1<CreateProjectPlanTask>() {
        public void apply(final CreateProjectPlanTask it) {
          it.setEngineerProject(EngineerProjectImpl.this);
          it.addOwner(tskOwner);
        }
      };
    CreateProjectPlanTask _doubleArrow = ObjectExtensions.<CreateProjectPlanTask>operator_doubleArrow(createProjectPlanTask, _function_1);
    taskDAO.createTask(_function, _doubleArrow);
  }
  
  @OneToMany(targetEntity = EngineerProjectJobImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "engineerProject")
  private Collection<EngineerProjectJob> projectJobs = new java.util.ArrayList<com.shrcl.engineerprocess.domain.EngineerProjectJob>();;
  
  public Collection<EngineerProjectJob> getProjectJobs() {
    return this.projectJobs;
  }
  
  public EngineerProjectJob createAndAddtoProjectJobs() {
    getProjectJobs().size();
    com.shrcl.engineerprocess.domain.EngineerProjectJob engineerProjectJob = new com.shrcl.engineerprocess.domain.impl.EngineerProjectJobImpl(this);
    getObjectFactory().create(engineerProjectJob);
    getProjectJobs().add(engineerProjectJob);
    engineerProjectJob.start();
    return engineerProjectJob;
    
  }
  
  public EngineerProjectJob createAndAddtoProjectJobs(final Procedure1<EngineerProjectJob> updater) {
    getProjectJobs().size();
    com.shrcl.engineerprocess.domain.EngineerProjectJob engineerProjectJob = new com.shrcl.engineerprocess.domain.impl.EngineerProjectJobImpl(this);
    getObjectFactory().create(engineerProjectJob);
    getProjectJobs().add(engineerProjectJob);
    updater.apply(engineerProjectJob);
    engineerProjectJob.start();
    return engineerProjectJob;
    
  }
  
  public EngineerProject removeAllProjectJobs() {
    for(EngineerProjectJob obj : this.projectJobs){
    	getObjectFactory().delete(obj);
    }
    this.projectJobs.clear();
    return this;	
    
  }
  
  public EngineerProject removeFromProjectJobs(final EngineerProjectJob engineerProjectJob) {
    this.projectJobs.remove(engineerProjectJob);
    getObjectFactory().delete(engineerProjectJob);
    return this;
    
  }
  
  public String getRCProjectName() {
    RCProject _project = this.tscCostEstimation==null?(RCProject)null:this.tscCostEstimation.getProject();
    String _name = _project==null?(String)null:_project.getName();
    return _name;
  }
  
  public String getRCProjectCode() {
    RCProject _project = this.tscCostEstimation==null?(RCProject)null:this.tscCostEstimation.getProject();
    String _code = _project==null?(String)null:_project.getCode();
    return _code;
  }
  
  public static EngineerProject create(final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerProject engineerProject = new com.shrcl.engineerprocess.domain.impl.EngineerProjectImpl(
    );
    objectFactory.create(engineerProject);
    engineerProject.start();
    return engineerProject;			
    
  }
  
  public static EngineerProject createEngineerProjectImpl(final IObjectFactory objectFactory, final Procedure1<EngineerProject> init) {
    com.shrcl.engineerprocess.domain.EngineerProject engineerProject = new com.shrcl.engineerprocess.domain.impl.EngineerProjectImpl(
    );
    objectFactory.create(engineerProject);
    init.apply(engineerProject);
    engineerProject.start();
    
    return engineerProject;			
    
  }
  
  public EngineerProjectProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerProjectProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerProjectProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
